package top.majuan.springboot3.service.auth.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.majuan.springboot3.aop.AuthInfo;
import top.majuan.springboot3.base.R;
import top.majuan.springboot3.dao.auth.TbActionMapper;
import top.majuan.springboot3.dao.auth.TbRoleActionMapper;
import top.majuan.springboot3.dao.auth.TbUserInfoMapper;
import top.majuan.springboot3.dao.auth.TbUserMapper;
import top.majuan.springboot3.entity.auth.TbAction;
import top.majuan.springboot3.entity.auth.TbRoleAction;
import top.majuan.springboot3.entity.auth.TbUser;
import top.majuan.springboot3.entity.auth.TbUserInfo;
import top.majuan.springboot3.exception.AppException;
import top.majuan.springboot3.interceptor.AppInterceptor;
import top.majuan.springboot3.service.RedisService;
import top.majuan.springboot3.service.auth.AuthService;
import top.majuan.springboot3.util.EncryptorUtils;

import java.util.UUID;

@Service
@Slf4j
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
    private final TbUserMapper tbUserMapper;
    private final TbUserInfoMapper tbUserInfoMapper;
    private final RedisService  redisService;
    private final TbActionMapper tbActionMapper;
    private final TbRoleActionMapper tbRoleActionMapper;

    @Override
    public TbUser queryById(Integer id) {
        return tbUserMapper.selectById(id);
    }

    @Override
    public TbUser queryName(String username) {
        QueryWrapper<TbUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        return tbUserMapper.selectOne(wrapper);
    }
//  @Transactional表示被注解的方法或者class要开启数据库事务，如果发生异常，则自动回滚事务
    @Transactional
    @Override
    public R<TbUser> reg(TbUser tbUser) {
        TbUser check = queryName(tbUser.getUsername());
        if (check != null) {
            return R.fail("用户名已存在",null);
        }
        // 强制清除id，启用自动增长
        tbUser.setId(null);
        // 处理密码加密
        tbUser.setSalt(EncryptorUtils.makeSalt());
        String pwd = EncryptorUtils.md5(tbUser.getPassword(), tbUser.getSalt());
        tbUser.setPassword(pwd);
        // 注册用户角色固定为2（普通用户）
        tbUser.setRole(2);
        int i =  tbUserMapper.insert(tbUser);
        log.debug("用户注册信息:{}",tbUser);
        if (i !=  1) {
            // 如果想打断事物，必须是抛出异常，spring会自动回滚事物
            throw AppException.create("用户基本信息添加失败");
//            return R.fail("注册失败，用户基本信息错误",null);
        }
        // 如果添加成功就要同步创建附加信息
        TbUserInfo  tbUserInfo = new TbUserInfo();
        tbUserInfo.setId(tbUser.getId());
        tbUserInfo.setSex("n");
        tbUserInfo.setInfo("");
        tbUserInfo.setPhone("");
        tbUserInfo.setEmail("");
        tbUserInfo.setImgurl("");
        i = tbUserInfoMapper.insert(tbUserInfo);
        if (i != 1) {
            throw AppException.create("用户附加信息添加失败");
        }
        return R.ok("注册成功",tbUser);
    }

    @Override
    public R<TbUser> login(TbUser tbUser) {
        TbUser check = queryName(tbUser.getUsername());
        if (check == null) {
            return R.fail("用户不存在",null);
        }
        // 校验密码
        String pwd = EncryptorUtils.md5(tbUser.getPassword(), check.getSalt());
        if (!check.getPassword().equalsIgnoreCase(pwd)) {
            return R.fail("密码错误",null);
        }
        // 登录成功,保存用户信息到redis中，并返回token
        String token = UUID.randomUUID().toString();
        redisService.save(token,check.getId(),TOKEN_TIMEOUT);
        R <TbUser> r = R.ok("登录成功",check.view());
        r.setToken(token);
        return r;
    }

    @Override
    public R<String> logout() {
        AuthInfo  authInfo = AppInterceptor.getAuthInfo();
        redisService.delete(authInfo.getToken());
        return R.ok("注销成功",null);
    }

    @Override
    public R<TbUser> info() {
        AuthInfo authInfo = AppInterceptor.getAuthInfo();
        if (authInfo.getUid() == null) {
            return R.fail("未登录",null);
        }
        TbUser user = queryById(authInfo.getUid());
        if (user == null) {
            return R.fail("没有登录信息",null);
        }
        return R.ok("",user.view());
    }

    /**
     * 校验用户访问权限
     *
     * @return 是否通过访问权限校验
     */
    @Override
    public boolean checkAuth() {
        // 获取请求中的认证信息
        AuthInfo authInfo = AppInterceptor.getAuthInfo();
        log.debug("请求中的认证信息:{}",authInfo);
        // 校验请求的api是否在权限的托管列表中
        QueryWrapper<TbAction> w1 = new QueryWrapper<>();
        w1.eq("method",authInfo.getMethod());
        w1.eq("mapping",authInfo.getMapping());
        TbAction tbAction = tbActionMapper.selectOne(w1);
        // 如果不存在，表示不被管制，直接通过
        if (tbAction == null) {
            return true;
        }
        log.debug("请求中的api信息:{}",tbAction);
        // 获取用户登录的信息
        if (authInfo.getUid() == null) {
            // 没有id就没有登录，直接拒绝
            return false;
        }
        TbUser  user = queryById(authInfo.getUid());
        log.debug("登录用户的信息:{}",user);
        // 获取用户的角色信息去角色权限表中验证权限
        QueryWrapper<TbRoleAction> w2 = new QueryWrapper<>();
        w2.eq("rid",user.getRole());
        w2.eq("aid",tbAction.getId());
        TbRoleAction tbRoleAction = tbRoleActionMapper.selectOne(w2);
        log.debug("用户角色认证信息:{}",tbRoleAction);
        // 存在就表示拥有权限
        return tbRoleAction != null;
    }
}
